package com.shanpin.shebao.admin.ip;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.URL;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;

public class IpAddressService {

//	public static String address(String ip) {
//		try {
//			String r = HttpClient.get("http://ip.taobao.com//service/getIpInfo.php?ip=" + ip);
//			if (StringUtils.isNotBlank(r)) {
//				TaoBaoIp tbip = JsonUtil.toT(r, TaoBaoIp.class);
//				if (null != tbip && tbip.getCode() == 0) {
//					TaoBaoIpData data = tbip.getData();
//					if (null != data) {
//						return data.getRegion() + " " 
//								+ data.getCity() + " (" 
//								+ data.getIsp() + ")";
//					}
//				}
//			}
//		} catch (IOException e) {
//			
//		}
//		return "";
//	}

    public static void main(String[] args){
    	System.out.println(IpAddressService.class.getResource("/"));
        System.out.println(Arrays.toString(IpAddressService.find("118.28.8.8")));
    }

    public static boolean enableFileWatch = false;

    private static int offset;
    private static int[] index = new int[256];
    private static ByteBuffer dataBuffer;
    private static ByteBuffer indexBuffer;
    private static Long lastModifyTime = 0L;
    private static File ipFile ;
    private static ReentrantLock lock = new ReentrantLock();

    static {
    	URL url = IpAddressService.class.getResource("/");
    	String path = url.getPath();
    	if (path.startsWith("file")) {
    		path = path.replace("file\\:", "");
    	}
    	System.out.println(path);
        ipFile = new File(path + "17monipdb.dat");
        load();
        if (enableFileWatch) {
            watch();
        }
    }

    public static String address(String ip) {
    	String[] as = find(ip);
    	if (null != as) {
    		if (as.length > 2) {
    			return as[1] + " " + as[2];
    		} else if (as.length > 1) {
    			return as[0] + " " + as[1];
    		}
    	}
    	return "";
    }
    
    public static String[] find(String ip) {
    	if(ip!=null && ip.length()>0 && ip.contains(".")) {
    		int ip_prefix_value = new Integer(ip.substring(0, ip.indexOf(".")));
            long ip2long_value  = ip2long(ip);
            int start = index[ip_prefix_value];
            int max_comp_len = offset - 1028;
            long index_offset = -1;
            int index_length = -1;
            byte b = 0;
            for (start = start * 8 + 1024; start < max_comp_len; start += 8) {
                if (int2long(indexBuffer.getInt(start)) >= ip2long_value) {
                    index_offset = bytesToLong(b, indexBuffer.get(start + 6), indexBuffer.get(start + 5), indexBuffer.get(start + 4));
                    index_length = 0xFF & indexBuffer.get(start + 7);
                    break;
                }
            }

            if(index_length == -1) {
            	index_length = 0;
            }
            byte[] areaBytes = new byte[index_length];

            lock.lock();
            try {
            	if(dataBuffer != null) {
            		int pos = offset + (int) index_offset - 1024;
            		if(pos < 0) {
            			pos = 0;
            		}
            		dataBuffer.position(pos);
                    dataBuffer.get(areaBytes, 0, index_length);
            	}
                
            } finally {
                lock.unlock();
            }
            
            return new String(areaBytes, Charset.forName("UTF-8")).split("\t", -1);
    	}
		return null;
        
    }


    public static void load(String filename, boolean strict) throws Exception {
        ipFile = new File(filename);
        if (strict) {
            int contentLength = Long.valueOf(ipFile.length()).intValue();
            if (contentLength < 512 * 1024) {
                throw new Exception("ip data file error.");
            }
        }
        load();
        if (enableFileWatch) {
            watch();
        }
    }

    private static void watch() {
        Executors.newScheduledThreadPool(1).scheduleAtFixedRate(new Runnable() {
            @Override
            public void run() {
                long time = ipFile.lastModified();
                if (time > lastModifyTime) {
                    lastModifyTime = time;
                    load();
                }
            }
        }, 1000L, 5000L, TimeUnit.MILLISECONDS);
    }

    private static void load() {
        lastModifyTime = ipFile.lastModified();
        FileInputStream fin = null;
        lock.lock();
        try {
            dataBuffer = ByteBuffer.allocate(Long.valueOf(ipFile.length()).intValue());
            fin = new FileInputStream(ipFile);
            int readBytesLength;
            byte[] chunk = new byte[4096];
            while (fin.available() > 0) {
                readBytesLength = fin.read(chunk);
                dataBuffer.put(chunk, 0, readBytesLength);
            }
            dataBuffer.position(0);
            int indexLength = dataBuffer.getInt();
            byte[] indexBytes = new byte[indexLength];
            dataBuffer.get(indexBytes, 0, indexLength - 4);
            indexBuffer = ByteBuffer.wrap(indexBytes);
            indexBuffer.order(ByteOrder.LITTLE_ENDIAN);
            offset = indexLength;

            int loop = 0;
            while (loop++ < 256) {
                index[loop - 1] = indexBuffer.getInt();
            }
            indexBuffer.order(ByteOrder.BIG_ENDIAN);
        } catch (IOException ioe) {
            ioe.printStackTrace();
        } finally {
            try {
                if (fin != null) {
                    fin.close();
                }
            } catch (IOException e){
                e.printStackTrace();
            }
            lock.unlock();
        }
    }

    private static long bytesToLong(byte a, byte b, byte c, byte d) {
        return int2long((((a & 0xff) << 24) | ((b & 0xff) << 16) | ((c & 0xff) << 8) | (d & 0xff)));
    }

    private static int str2Ip(String ip)  {
        String[] ss = ip.split("\\.");
        int a, b, c, d;
        a = Integer.parseInt(ss[0]);
        b = Integer.parseInt(ss[1]);
        c = Integer.parseInt(ss[2]);
        d = Integer.parseInt(ss[3]);
        return (a << 24) | (b << 16) | (c << 8) | d;
    }

    private static long ip2long(String ip)  {
        return int2long(str2Ip(ip));
    }

    private static long int2long(int i) {
        long l = i & 0x7fffffffL;
        if (i < 0) {
            l |= 0x080000000L;
        }
        return l;
    }
}



class TaoBaoIp {
	private int code;
	private TaoBaoIpData data;

	public int getCode() {
		return code;
	}

	public void setCode(int code) {
		this.code = code;
	}

	public TaoBaoIpData getData() {
		return data;
	}

	public void setData(TaoBaoIpData data) {
		this.data = data;
	}

}

class TaoBaoIpData {
	private String country;
	private String country_id;
	private String area;
	private String area_id;
	private String region;
	private String region_id;
	private String city;
	private String city_id;
	private String county;
	private String county_id;
	private String isp;
	private String isp_id;
	private String ip;

	public String getCountry() {
		return country;
	}

	public void setCountry(String country) {
		this.country = country;
	}

	public String getCountry_id() {
		return country_id;
	}

	public void setCountry_id(String country_id) {
		this.country_id = country_id;
	}

	public String getArea() {
		return area;
	}

	public void setArea(String area) {
		this.area = area;
	}

	public String getArea_id() {
		return area_id;
	}

	public void setArea_id(String area_id) {
		this.area_id = area_id;
	}

	public String getRegion() {
		return region;
	}

	public void setRegion(String region) {
		this.region = region;
	}

	public String getRegion_id() {
		return region_id;
	}

	public void setRegion_id(String region_id) {
		this.region_id = region_id;
	}

	public String getCity() {
		return city;
	}

	public void setCity(String city) {
		this.city = city;
	}

	public String getCity_id() {
		return city_id;
	}

	public void setCity_id(String city_id) {
		this.city_id = city_id;
	}

	public String getCounty() {
		return county;
	}

	public void setCounty(String county) {
		this.county = county;
	}

	public String getCounty_id() {
		return county_id;
	}

	public void setCounty_id(String county_id) {
		this.county_id = county_id;
	}

	public String getIsp() {
		return isp;
	}

	public void setIsp(String isp) {
		this.isp = isp;
	}

	public String getIsp_id() {
		return isp_id;
	}

	public void setIsp_id(String isp_id) {
		this.isp_id = isp_id;
	}

	public String getIp() {
		return ip;
	}

	public void setIp(String ip) {
		this.ip = ip;
	}

}
